/*
 *
 *   Blah
 *
 */

#include <stdio.h>
#include <stdlib.h>


/* #include <linux/types.h> */

/*
#include <string.h>
#include <signal.h>
*/


#include "foo.h"


/*
typedef union _cell {
  struct {
    uint64_t oct;
  };
  struct {
    uint32_t q1;
    uint32_t q0;
  };
  struct {
    uint16_t w3;
    uint16_t w2;
    uint16_t w1;
    uint16_t w0;
  };
  struct {
    uint8_t b7;
    uint8_t b6;
    uint8_t b5;
    uint8_t b4;
    uint8_t b3;
    uint8_t b2;
    uint8_t b1;
    uint8_t b0;
  };
} cell;
*/


/* typedef struct { */
/*   unsigned long tag: 16; */
/*   unsigned long long body: 48; */
/* } Q; */


/* typedef struct { */
/*   unsigned int gc: 2; */
/*   unsigned int cdrcode: 2; */
/*   unsigned long tag: 12; */
/*   unsigned long long body: 48; */
/* } Q; */


/* this should really be a union with a MAXINT */
typedef struct Q {
  unsigned int gc: 2;
  unsigned int cdrcode: 2;
  unsigned int tag: 12;
  struct Q *ptr;
} Q, *any;

/* tag types */
#define NUMBER      0
#define SYMBOL      1
#define LIST        2
#define VARIABLE    3 
#define PROCEDURE   4
#define IF          5
#define COMBINATION 6
/* ... */
#define FUNCALL     7
#define CONS        8
#define CAR         9
#define CDR        10
/* ... */

/* for return: */
#define IF2        11
#define EVCOM3     12



#define nextq(X) ((Q*)((X)+sizeof(Q)))


Q *NIL;


/* system memory */
Q mem[100];


/* typedef unsigned long int addr; */

/* typedef uint64_t Q; */
/* #define qtag(X)    (((X)>>48)&0xFFFF) */
/* #define qbody(X)   ((X)&0xFFFFFFFFFFFF) */

/****************************************************************************


01234567 01234567 01234567 01234567 01234567 01234567 01234567 01234567
######## ######## ######## ######## ######## ######## ######## ########
TTTTTTTT TTTTTTTT AAAAAAAA AAAAAAAA AAAAAAAA AAAAAAAA AAAAAAAA AAAAAAAA
\_______________/ \___________________________________________________/
   16 bit tag                   48 bit pointer or fixint

****************************************************************************/


void err() {
  printf("Argh!\n");
  exit(1);
}


void debug_print_q(Q *q) {
  printf("GC: %x, CDR-code: %x, Tag: %x, Body: %x\n", q->gc, q->cdrcode, q->tag, q->ptr);
  return;
}


Q car(Q q) {
  return q->ptr;
}


/* test w/o cdr-coding? at first. */

Q cdr(Q q) {
  switch (q->cdrcode) {
    case 0:                                                 /* CDR-NIL */
      return NIL;
    case 1:
      return nextq(q)->ptr;                                 /* CDR-NORMAL */
    case 2:                                                 /* CDR-NEXT */
      return nextq(q);
    case 3:                                                 /* CDR-MISC */
      err();
      break;
  }
  err();
}


void evaluator() { /* arguments/returns??? EXP/VAL? */
  Q _exp, _env, _val, _args, _clink;

 eval:
  switch (_exp->tag) {
    case NUMBER:
    case SYMBOL:
    case LIST:
      goto self;
    case VARIABLE:
      goto lookup;
    case PROCEDURE:
      goto proc;
    case IF:
      goto if1;
    case COMBINATION:
      goto evcomb;
    /* ... */
  }
  splat();

 self:
  _val = exp;
  goto ev_return;

 proc:
  _val = t_cons(CLOSURE, _exp, _env);
  goto ev_return;

 if1:
  _val = cdr(_exp);
  _clink = cons(_env, _clink);
  _exp = car(exp);
  goto eval;

 if2:
  _exp = car(_clink);
  _clink = cdr(_clink);
  _env = car(_clink);
  _clink = cdr(_clink);
  if (_val == NIL) {  /* should NIL be a type? */
    _exp = cdr(_exp);
  } else {
    _exp = car(_exp);
  }
  goto eval;

 evcomb:
  _args = NIL; /* '() */
 evcom1:
  switch(_exp->tag) {
    case COMBINATION:
      goto evcom2;
    case FUNCALL:
      goto call;
    case CONS:
      goto evcons;
    case CAR:
      goto evcar;
    case CDR:
      goto evcdr;
    /* ... */
  }
  splat();

 evcom2:
  _clink = cons(_env, _clink);
  _clink = cons(_args, _clink);
  _val = cdr(_exp);
  _clink = t_cons(EVCOM3, _val, _clink);
  _exp = car(_exp);
  goto eval;

 evcom3:
  _exp = car(_clink);
  _clink = cdr(_clink);
  _args = car(_clink);
  _clink = cdr(_clink);
  _env = car(_clink);
  _clink = cdr(_clink);
  _args = cons(_val, _args);
  goto evcom1;

 call:
  _exp = car(_val);
  _val = cdr(_val);
  _env = cons(_args, _val);
  goto eval;

 evcons:
  _args = cdr(_args);
  _args = car(_args);
  _val = cons(_args, _val);
  goto evreturn;

 evcar:
  _val = car(_val);
  goto evreturn;

 evcdr:
  _val = cdr(_val);
  goto evreturn;

 evreturn:
  switch(_clink->tag) {
    case IF2:
      goto if2;
    case EVCOM3:
      goto evcom3;
  }
  splat();

}

void splat() {
  exit(1);
}



int main() {
  
  Q Test, _nil;

  NIL = &_nil;

  
/*   printf("size: %d\n", sizeof(Test)); */
  
  printf("Start.\n");

  debug_print_q(&Test);

  
  
  
  return 0;
}
